home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 March / macformat-022.iso / Shareware City / Graphics / SPD / Sources / mount.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-10  |  8.1 KB  |  266 lines  |  [TEXT/R*ch]

  1. /*
  2.  * mount.c - creates a fractal mountain, using Carpenter's method with a
  3.  *    different extension to square grids.  A pyramid of 4 glass spheres
  4.  *    is added in front of the mountain.  One light source.
  5.  *
  6.  *    NOTE: the hashing function used to generate the database originally is
  7.  *    faulty.  The function causes repetition to occur within the fractal
  8.  *    mountain (obviously not very fractal behavior!).  A new hashing
  9.  *    function is included immediately after the old one:  merely define
  10.  *    NEW_HASH if you want to use a better hashing function.  To perform ray
  11.  *    tracing comparison tests you should still use the old, faulty database
  12.  *    (it may have repetition, but it's still a good test image).
  13.  *
  14.  * Author:  Eric Haines, 3D/Eye, Inc.
  15.  *
  16.  * size_factor determines the number of objects output.
  17.  *    Total triangular polygons = 2 * (4**size_factor)
  18.  *
  19.  *    size_factor    # triangles    # spheres
  20.  *         1             8             4
  21.  *         2            32             4
  22.  *         3           128             4
  23.  *
  24.  *         6          8192             4
  25.  */
  26.  
  27. #include <stdio.h>
  28. #include <math.h>
  29. #include <stdlib.h>    /* atoi */
  30. #include "def.h"
  31. #include "drv.h"    /* display_close() */
  32. #include "lib.h"
  33.  
  34. /* Determine which raytracer we will use */
  35. static int raytracer_format = OUTPUT_RT_DEFAULT;
  36. /* output format determines if polygons or true surfaces are used */
  37. static int output_format = OUTPUT_CURVES;
  38.  
  39.  
  40. /* Complexity of the image */
  41. static int size_factor = 6;
  42.  
  43. #ifdef OUTPUT_TO_FILE
  44. static FILE * stdout_file = NULL;
  45. #else
  46. #define stdout_file stdout
  47. #endif /* OUTPUT_TO_FILE */
  48.  
  49. /* to use the corrected hashing function, uncomment this next line */
  50. /* #define NEW_HASH */
  51.  
  52. /* fractal dimension - affects variance of z.  Between 2 and 3 */
  53. #define    FRACTAL_DIMENSION    2.2
  54. /* change MOUNTAIN_NO to get a different mountain */
  55. #define    MOUNTAIN_NO        21
  56.  
  57. /* lower left corner and width of mountain definitions */
  58. #define    X_CORNER    -1.0
  59. #define    Y_CORNER    -1.0
  60. #define    WIDTH         2.0
  61.  
  62. #ifndef NEW_HASH
  63.  
  64. /* Hashing function to get a seed for the random number generator. */
  65. /* This is the old, buggy hashing function - use it if you wish to
  66.  * obtain the same image as in the November 1987 IEEE CG&A article. */
  67. #define    hash_rand(A,B,C)    ( ( (((unsigned long)(A))<<(23-(C))) +    \
  68.                     (((unsigned long)(B))<<(15-(C)))    \
  69.                   + (((unsigned long)(A))<<(7-(C))) ) & 0xffff)
  70. #else
  71.  
  72. /* New, corrected hashing function.  Use for a true fractal mountain */
  73. /* 134456 is M1 in routine lib_gauss_rand() */
  74. #define    hash_rand(A,B,C)    ( ( C <= 15 ) ?                \
  75.                   ( ABSOLUTE(                \
  76.                     (((unsigned long)(A))<<(31-(C))) +    \
  77.                     (((unsigned long)(B))<<(15-(C))) )    \
  78.                   % 134456 ) :                \
  79.                   ( ABSOLUTE(                \
  80.                     (((unsigned long)(A))<<(31-(C))) +    \
  81.                     (((unsigned long)(B))>>((C)-15)) )    \
  82.                   % 134456 ) )
  83.                   )
  84. #endif
  85.  
  86. static    double  Roughness ;
  87.  
  88. /* create a pyramid of crystal spheres */
  89. void
  90. create_spheres(center)
  91.     COORD4 center;
  92. {
  93.     int i;
  94.     double angle;
  95.     COORD3 axis, pt, new_pt;
  96.     COORD4 sphere;
  97.     MATRIX mx;
  98.  
  99.     SET_COORD3(axis, 1.0, 1.0, 0.0);
  100.     (void)lib_normalize_vector(axis);
  101.     angle = acos((double)(-1.0/3.0));
  102.  
  103.     /* set center of pyramid */
  104.     SET_COORD3(pt, 0.0, 0.0, center[W] * sqrt((double)(3.0/2.0)));
  105.  
  106.     COPY_COORD4(sphere, center);
  107.     ADD2_COORD3(sphere, pt);
  108.     lib_output_sphere(sphere, output_format);
  109.  
  110.     lib_create_axis_rotate_matrix(mx, axis, angle);
  111.     lib_transform_vector(new_pt, pt, mx);
  112.  
  113.     for (i = 0; i < 3; i++) {
  114.     lib_create_rotate_matrix(mx, Z_AXIS, (double)i * 2.0 * PI / 3.0);
  115.     lib_transform_vector(sphere, new_pt, mx);
  116.     ADD2_COORD3(sphere, center);
  117.     lib_output_sphere(sphere, output_format);
  118.     }
  119. }
  120.  
  121. /*
  122.  * Build mountain section.  If at width > 1, split quadrilateral into four
  123.  * parts.  Else if at width == 1, output quadrilateral as two triangles.
  124.  */
  125. void
  126. grow_mountain(fnum_pts, width, ll_x, ll_y, ll_fz, lr_fz, ur_fz, ul_fz)
  127.     double fnum_pts;
  128.     int width;
  129.     int ll_x;
  130.     int ll_y ;
  131.     double ll_fz;
  132.     double lr_fz;
  133.     double ur_fz;
  134.     double ul_fz;
  135. {
  136.     long iz;
  137.     int half_width, num_tri, num_tri_vert, num_vert;
  138.     double l_fx, r_fx, l_fy, u_fy;
  139.     double lower_fz, right_fz, upper_fz, left_fz, middle_fz;
  140.     double rise_height, hside_length;
  141.     COORD3 tri_vert[3];
  142.  
  143.     if ( width == 1 ) {
  144.     /* calculate x and y coordinates of corners */
  145.     l_fx = X_CORNER + (double)ll_x * WIDTH / fnum_pts;
  146.     r_fx = X_CORNER + (double)(ll_x+1) * WIDTH / fnum_pts;
  147.     l_fy = Y_CORNER + (double)ll_y * WIDTH / fnum_pts;
  148.     u_fy = Y_CORNER + (double)(ll_y+1) * WIDTH / fnum_pts;
  149.  
  150.     /* output two triangles for section */
  151.     for (num_tri = 0; num_tri < 2; num_tri++) {
  152.         for (num_vert = 0; num_vert < 3; num_vert++) {
  153.         num_tri_vert = (num_vert + num_tri * 2) % 4;
  154.         switch (num_tri_vert) {
  155.             case 0:
  156.             SET_COORD3(tri_vert[num_vert], l_fx, l_fy, ll_fz);
  157.             break;
  158.             case 1:
  159.             SET_COORD3(tri_vert[num_vert], r_fx, l_fy, lr_fz);
  160.             break;
  161.             case 2:
  162.             SET_COORD3(tri_vert[num_vert], r_fx, u_fy, ur_fz);
  163.             break;
  164.             case 3:
  165.             SET_COORD3(tri_vert[num_vert], l_fx, u_fy, ul_fz);
  166.             break;
  167.         }
  168.         }
  169.         lib_output_polygon(3, tri_vert);
  170.     }
  171.     } else {
  172.     /* subdivide edges and move in z direction */
  173.     half_width = width>>1;
  174.     hside_length = (double)half_width * WIDTH / fnum_pts;
  175.     rise_height = hside_length * Roughness;
  176.  
  177.     /* for each midpoint, find z */
  178.     iz = MOUNTAIN_NO + hash_rand(ll_x + half_width, ll_y, size_factor);
  179.     lower_fz = (ll_fz + lr_fz) / 2.0 + rise_height * lib_gauss_rand(iz);
  180.     iz = MOUNTAIN_NO + hash_rand(ll_x + width, ll_y + half_width,
  181.                       size_factor);
  182.     right_fz = ( lr_fz + ur_fz ) / 2.0 + rise_height * lib_gauss_rand(iz);
  183.     iz = MOUNTAIN_NO + hash_rand(ll_x + half_width, ll_y + width,
  184.                       size_factor);
  185.     upper_fz = ( ur_fz + ul_fz ) / 2.0 + rise_height * lib_gauss_rand(iz);
  186.     iz = MOUNTAIN_NO + hash_rand( ll_x, ll_y + half_width, size_factor);
  187.     left_fz = ( ul_fz + ll_fz ) / 2.0 + rise_height * lib_gauss_rand(iz);
  188.     iz = MOUNTAIN_NO + hash_rand(ll_x + half_width, ll_y + half_width,
  189.                       size_factor);
  190.     middle_fz = ( ll_fz + lr_fz + ur_fz + ul_fz ) / 4.0 +
  191.               1.4142136 * rise_height * lib_gauss_rand(iz);
  192.  
  193.     /* check subsections for subdivision or output */
  194.     PLATFORM_MULTITASK();
  195.     grow_mountain(fnum_pts, half_width, ll_x, ll_y,
  196.               ll_fz, lower_fz, middle_fz, left_fz);
  197.     grow_mountain(fnum_pts, half_width, ll_x+half_width, ll_y,
  198.               lower_fz, lr_fz, right_fz, middle_fz);
  199.     grow_mountain(fnum_pts, half_width, ll_x+half_width, ll_y+half_width,
  200.               middle_fz, right_fz, ur_fz, upper_fz);
  201.     grow_mountain(fnum_pts, half_width, ll_x, ll_y+half_width,
  202.               left_fz, middle_fz, upper_fz, ul_fz);
  203.     }
  204. }
  205.  
  206. int
  207. main(argc,argv)
  208.     int argc;
  209.     char *argv[];
  210. {
  211.     int num_pts;
  212.     double ratio;
  213.     COORD3 back_color, obj_color;
  214.     COORD3 from, at, up;
  215.     COORD4 light, center;
  216.  
  217.     PLATFORM_INIT(SPD_MOUNT);
  218.  
  219.     /* Start by defining which raytracer we will be using */
  220.     if ( lib_gen_get_opts( argc, argv,
  221.             &size_factor, &raytracer_format, &output_format )) {
  222.     return EXIT_FAIL;
  223.     }
  224.     if ( lib_open( raytracer_format, "Mount.out" ) ) {
  225.     return EXIT_FAIL;
  226.     }
  227.  
  228.     /* output background color - UNC sky blue */
  229.     /* NOTE: Do this BEFORE lib_output_viewpoint(), for display_init() */
  230.     SET_COORD3(back_color, 0.078, 0.361, 0.753);
  231.     lib_output_background_color(back_color);
  232.  
  233.     /* output viewpoint */
  234.     SET_COORD3(from, -1.6, 1.6, 1.7);
  235.     SET_COORD3(at, 0.0, 0.0, 0.0);
  236.     SET_COORD3(up, 0.0, 0.0, 1.0);
  237.     lib_output_viewpoint(from, at, up, 45.0, 1.0, 0.01, 512, 512);
  238.  
  239.     /* output light sources */
  240.     SET_COORD4(light, -100.0, -100.0, 100.0, 1.0);
  241.     lib_output_light(light);
  242.  
  243.     /* set up crystal sphere color - clear white */
  244.     SET_COORD3(obj_color, 1.0, 1.0, 1.0);
  245.     lib_output_color(NULL, obj_color, 0.0, 0.1, 0.1, 0.4, 5.0, 0.9, 1.5);
  246.  
  247.     /* output crystal spheres */
  248.     SET_COORD4(center, -0.8, 0.8, 1.00, 0.17);
  249.     create_spheres(center);
  250.  
  251.     /* set up mountain color - grey */
  252.     SET_COORD3(obj_color, 0.5, 0.45, 0.35);
  253.     lib_output_color(NULL, obj_color, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0);
  254.  
  255.     /* grow mountain */
  256.     num_pts = 1<<size_factor;
  257.     ratio = 2.0 / exp((double)(log((double)2.0) / (FRACTAL_DIMENSION-1.0)));
  258.     Roughness = sqrt((double)(SQR(ratio) - 1.0));
  259.     grow_mountain((double)num_pts, num_pts, 0, 0, 0.0, 0.0, 0.0, 0.0);
  260.  
  261.     lib_close();
  262.  
  263.     PLATFORM_SHUTDOWN();
  264.     return EXIT_SUCCESS;
  265. }
  266.